﻿using Autofac;
using Autofac.Configuration;
using Autofac.Integration.Wcf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading;
using TestService.Common;
using TestService.Common.Config;
using TestService.Common.IoC;
using TestService.Contract;

namespace TestService.Host
{
    class Service
    {
        public static void Start()
        {
            Log.Info("服务初始化...");
            // 启动Server主线程
            Thread server = new Thread(ServerRunnable.Instance.Run);
            server.Start();
            BuildWcfContainer();

            StartServiceHost();
            StartAllDuplexValidateService();
        }

        public static void Stop()
        {

        }

        #region Autofac 注入

        public static void BuildWcfContainer()
        {
            var builder = new ContainerBuilder();
            builder.RegisterModule(new ConfigurationSettingsReader("autofac"));

            IoCFactory.Instance.CurrentContainter = builder.Build();
            AutofacHostFactory.Container = IoCFactory.Instance.CurrentContainter;
        }

        #endregion

        private static void StartServiceHost()
        {
            try
            {
                TestServiceSection services = TestServiceSection.GetConfig();
                foreach (TheKeyValue item in services.KeyValues)
                {
                    Type serviceType = Type.GetType(item.Service);
                    Type contractType = Type.GetType(item.Contract, true, true);
                    StartService(item.Uri, contractType, serviceType);
                }
            }
            catch (ObjectDisposedException objDisposedEx)
            {
                Log.Error(objDisposedEx);
            }
            catch (InvalidOperationException invalidOpEx)
            {
                Log.Error(invalidOpEx);
            }
            catch (CommunicationObjectFaultedException commObjFaultedEx)
            {
                Log.Error(commObjFaultedEx);
            }
            catch (System.ServiceProcess.TimeoutException tmOutEx)
            {
                Log.Error(tmOutEx);
            }
            catch (Exception ex)
            {
                Log.Error(ex);
            }
        }


        public static void StartService(string uri, Type contract, Type serviceType)
        {
            try
            {
                ServiceHost host = new ServiceHost(serviceType);
                // WCF 注入配置
                host.AddDependencyInjectionBehavior(contract, IoCFactory.Instance.CurrentContainter);

                NetTcpBinding banding = new NetTcpBinding
                {
                    MaxBufferSize = int.MaxValue,
                    MaxReceivedMessageSize = int.MaxValue,
                    Security = new NetTcpSecurity { Mode = SecurityMode.None }
                };

                banding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas();
                banding.ReaderQuotas.MaxArrayLength = int.MaxValue;
                banding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
                banding.ReaderQuotas.MaxDepth = int.MaxValue;
                banding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
                host.AddServiceEndpoint(contract, banding, uri);
                //如果需要带上验证信息，则加上对应处理

                host.Faulted += ServiceHost_Faulted;
                host.Open();
                Log.Info("已启动" + serviceType.Name + "服务...");
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("启动{0}服务异常:{1}", serviceType.Name, ex.Message));
            }
        }

        /// <summary>
        /// 服务以外中断处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void ServiceHost_Faulted(object sender, EventArgs e)
        {
            var serviceHost = sender as ServiceHost;
            Log.Warn(string.Format("{0} 服务意外中断.  正在尝试重启...", serviceHost.Description.Name));
            RestartServiceHost(serviceHost);
        }

        #region 双工验证服务

        private static void StartAllDuplexValidateService()
        {
            StartDuplexValidateService<IEventBroker>();
        }

        private static void StopAllDuplexValidateService()
        {
            StopDuplexValidateService<IEventBroker>();
        }

        private static void StartDuplexValidateService<T>()
        {
            T service = IoCFactory.Instance.CurrentContainter.Resolve<T>();
            ServiceHost _host = new ServiceHost(service);
            // 加入到容器中
            _host.AddDependencyInjectionBehavior<T>(IoCFactory.Instance.CurrentContainter);
            StartServiceHost(_host);
        }

        private static void StopDuplexValidateService<T>()
        {
            T service = IoCFactory.Instance.CurrentContainter.Resolve<T>();
            ServiceHost _host = new ServiceHost(service);
            StopServiceHost(_host);
        }

        #endregion

        #region 单个服务操作
        private static void StartServiceHost(ServiceHostBase serviceHost)
        {
            try
            {
                serviceHost.Open();
                serviceHost.Faulted += ServiceHost_Faulted;
                Log.Info(string.Format("已启动{0}服务...", serviceHost.Description.Name));
            }
            catch (ObjectDisposedException objDisposedEx)
            {
                Log.Error(objDisposedEx);
            }
            catch (InvalidOperationException invalidOpEx)
            {
                Log.Error(invalidOpEx);
            }
            catch (CommunicationObjectFaultedException commObjFaultedEx)
            {
                Log.Error(commObjFaultedEx);
            }
            catch (System.ServiceProcess.TimeoutException tmOutEx)
            {
                Log.Error(tmOutEx);
            }
            catch (Exception ex)
            {
                Log.Error(ex);
            }
        }

        private static void StopServiceHost(ServiceHostBase serviceHost)
        {
            if (serviceHost.State != CommunicationState.Closed)
            {
                if (serviceHost.State != CommunicationState.Faulted)
                {
                    serviceHost.Close();
                    Log.Info(string.Format("{0} 关闭.", serviceHost.Description.Name));
                }
                else
                {
                    serviceHost.Abort();
                    Log.Info(string.Format("{0} 终止.", serviceHost.Description.Name));
                }
            }
        }

        private static void RestartServiceHost(ServiceHost serviceHost)
        {
            StopServiceHost(serviceHost);
            StartServiceHost(serviceHost);
        }

        #endregion
    }
}
